package cn.whb.hrm.controller;


import cn.whb.hrm.config.HighlightResultMapper;
import cn.whb.hrm.doc.CourseDoc;
import cn.whb.hrm.query.CourseDocQuery;
import cn.whb.hrm.repository.CourseDocRepository;
import cn.whb.hrm.util.AjaxResult;
import cn.whb.hrm.utils.PageList;
import cn.whb.hrm.vo.AggVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PreDestroy;
import javax.swing.text.Highlighter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/search")
public class CourseDocController {

    @Autowired
    private CourseDocRepository courseDocRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @PostMapping("/courseOnline")
    @PreAuthorize("hasAuthority('courseDoc:add')")
    public AjaxResult courseOnline(@RequestBody CourseDoc doc){
        courseDocRepository.save(doc);
        return AjaxResult.me();
    }

    @GetMapping("/courseOffline/{id}")
    public AjaxResult courseOffLine(@PathVariable("id") Long id){
        courseDocRepository.deleteById(id);
        return AjaxResult.me();
    }

    @PostMapping("/queryCourses")
    public AjaxResult queryCourses(@RequestBody CourseDocQuery docQuery){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //聚合查询
        builder.addAggregation(AggregationBuilders.terms("tenantNameAgg").field("tenantName").order(Terms.Order.count(false)).size(20));
        builder.addAggregation(AggregationBuilders.terms("couseTypeAgg").field("courseTypeName").order(Terms.Order.count(false)).size(20));
        //高亮
        //设置高亮显示
        HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'><b>").postTags("</b></font>");
        builder.withHighlightFields(field);
        //过滤和高级查询
        //高级查询
        String keyword = docQuery.getKeyword();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(keyword)){
            boolQuery.must(QueryBuilders.multiMatchQuery(keyword,"name","courseTypeName","gradeName"));
        }
        //过滤
        //通过courseType筛选
        String courseTypeName = docQuery.getCourseTypeName();
        if(!StringUtils.isEmpty(courseTypeName)){
            boolQuery.filter(QueryBuilders.termQuery("courseTypeName", courseTypeName));
        }
        //通过courseType筛选
        String tenantName = docQuery.getTenantName();
        if(!StringUtils.isEmpty(tenantName)){
            boolQuery.filter(QueryBuilders.termQuery("tenantName", tenantName));
        }
        //获取范围最小值
        Float min = docQuery.getPriceMin();
        if(min!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(min));
        }
        //获取范围最大值
        Float max = docQuery.getPriceMax();
        if(max!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(max));
        }
        builder.withQuery(boolQuery);
        //排序  根据哪个字段排序  排序方式
        //根据哪个字段排序
        String sortField = docQuery.getSortField();
        //三目运算。如果为空，默认用price字段排序，如果不为空，就用前端的字段排序
        sortField = StringUtils.isEmpty(sortField)?"price":sortField;
        //三目运算。如果前端返回的字段为desc，就用SortOrder.DESC，如果不是，就用SortOrder.ASC
        SortOrder sortOrder=SortOrder.DESC.toString().equals(docQuery.getSortType())?SortOrder.DESC:SortOrder.ASC;
        builder.withSort(new FieldSortBuilder(sortField).order(sortOrder));
        //分页查询
        builder.withPageable(PageRequest.of(docQuery.getPage()-1, docQuery.getRows()));
        //用repository进行查询
        //Page<CourseDoc> docPage = courseDocRepository.search(builder.build());
        //查询结构封装成pageList
        AggregatedPage<CourseDoc> docPage = elasticsearchTemplate.queryForPage(builder.build(), CourseDoc.class, highlightResultMapper);
        //封装聚合查询结果
        HashMap<String, ArrayList<AggVo>> map = new HashMap<>();
        //查询机构发布了多少课程
        StringTerms tenantNameAgg = (StringTerms)docPage.getAggregation("tenantNameAgg");
        List<StringTerms.Bucket> tBucket = tenantNameAgg.getBuckets();
        ArrayList<AggVo> tList = new ArrayList<>();
        tBucket.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo(bucket.getKeyAsString(), bucket.getDocCount());
            tList.add(aggVo);
        });
        //封装成map
        map.put("tlist", tList);
        //查询每种课程类型有多少个课程
        StringTerms couseTypeAgg = (StringTerms)docPage.getAggregation("couseTypeAgg");
        List<StringTerms.Bucket> cBucket = couseTypeAgg.getBuckets();
        ArrayList<AggVo> cList = new ArrayList<>();
        cBucket.stream().forEach(bucket -> {
            AggVo aggVo = new AggVo(bucket.getKeyAsString(), bucket.getDocCount());
            cList.add(aggVo);
        });
        map.put("clist", cList);
        PageList<CourseDoc> pageList = new PageList<>(docPage.getTotalElements(),docPage.getContent(),map);
        return AjaxResult.me().setResultObj(pageList);
    }
}
